package com.h2.ref.server.util.sec;

import java.io.IOException;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.util.UrlPathHelper;

public class UrlProcessingAuthFilter<T extends Filter> implements Filter {

   /**
    * The URLs destination that this filter intercepts and processes (usually
    * something like <code>/j_spring_security_check</code>)
    */
   private List<String> _filterProcessesUrls;
   
   private PathMatcher _pathMatcher = new AntPathMatcher();
   
   private UrlPathHelper _urlPathHelper = new UrlPathHelper();
   
   private T _delegate;
   
   private EntryPointFilter _entryPointFilter;
   
   ////
   ////
   
   /* (non-Javadoc)
    * @see javax.servlet.Filter#destroy()
    */
   @Override
   public void destroy() {
      getDelegate().destroy();
   }

   /* (non-Javadoc)
    * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
    */
   @Override
   public void init(FilterConfig config) throws ServletException {
      getDelegate().init(config);
   }
   
   /* (non-Javadoc)
    * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
    *   javax.servlet.ServletResponse, javax.servlet.FilterChain)
    */
   @Override
   public void doFilter(ServletRequest req, ServletResponse res,
         final FilterChain chain) throws IOException, ServletException {

      HttpServletRequest request = (HttpServletRequest) req;
      HttpServletResponse response = (HttpServletResponse) res;

      if (!requiresAuthentication(request, response)) {
         //process chain as normal
         chain.doFilter(request, response);
         return;
      }
      
      if(getEntryPointFilter() == null) {
         getDelegate().doFilter(req, res, chain);
      }
      else {
         getDelegate().doFilter(req, res, new FilterChain() {
            
            @Override
            public void doFilter(ServletRequest request, ServletResponse response)
                  throws IOException, ServletException {
               getEntryPointFilter().doFilter(request, response, chain);
            }
         });
      }
   }

   /**
    * Indicates whether this filter should attempt to process a login request
    * for the current invocation.
    * <p>
    * It strips any parameters from the "path" section of the request URL (such
    * as the jsessionid parameter in
    * <em>http://host/myapp/index.html;jsessionid=blah</em>) before matching
    * against the <code>filterProcessesUrl</code> property.
    * <p>
    * Subclasses may override for special requirements, such as Tapestry
    * integration.
    * 
    * @return <code>true</code> if the filter should attempt authentication,
    *         <code>false</code> otherwise.
    */
   protected boolean requiresAuthentication(HttpServletRequest request,
         HttpServletResponse response) {
      
      String lookupPath = getUrlPathHelper().getPathWithinApplication(request);
      
      for (String filterUrl : getFilterProcessesUrls()) {
         if(getPathMatcher().match(filterUrl, lookupPath)){
            return true;
         }
      }
      return false;
   }

   /**
    * @return the filterProcessesUrls
    */
   public List<String> getFilterProcessesUrls() {
      return _filterProcessesUrls;
   }

   /**
    * @param filterProcessesUrls the filterProcessesUrl to set
    */
   public void setFilterProcessesUrls(List<String> filterProcessesUrls) {
      _filterProcessesUrls = filterProcessesUrls;
   }

   /**
    * @return the pathMatcher
    */
   public PathMatcher getPathMatcher() {
      return _pathMatcher;
   }

   /**
    * @param pathMatcher the pathMatcher to set
    */
   public void setPathMatcher(PathMatcher pathMatcher) {
      _pathMatcher = pathMatcher;
   }

   /**
    * @return the urlPathHelper
    */
   public UrlPathHelper getUrlPathHelper() {
      return _urlPathHelper;
   }

   /**
    * @param urlPathHelper the urlPathHelper to set
    */
   public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
      _urlPathHelper = urlPathHelper;
   }

   /**
    * @return the delegate
    */
   public T getDelegate() {
      return _delegate;
   }

   /**
    * @param delegate the delegate to set
    */
   public void setDelegate(T delegate) {
      _delegate = delegate;
   }

   /**
    * @return the entryPointFilter
    */
   public EntryPointFilter getEntryPointFilter() {
      return _entryPointFilter;
   }

   /**
    * @param entryPointFilter the entryPointFilter to set
    */
   public void setEntryPointFilter(EntryPointFilter entryPointFilter) {
      _entryPointFilter = entryPointFilter;
   }
}
